﻿<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>h5斗地主</title>

	<link href="https://cdn.bootcss.com/iview/3.1.4/styles/iview.css" rel="stylesheet">
	<link href="https://cdn.bootcss.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet">

	<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>
	<script src="https://cdn.bootcss.com/vue/2.5.17/vue.min.js"></script>
	<script src="https://cdn.bootcss.com/iview/3.1.4/iview.min.js"></script>

</head>

<body class="hold-transition login-page">

	<div id="app">

		<div v-if="stage == '未开始'" style="background:#eee;">
			<Card :bordered="false">
				<p slot="title">.NETCore斗地主服务端 + HTML5前端</p>
				<div>
					<p>本项目最终目标为AI斗地主，机器人最优方案对打。</p>
					
					<p>声明：本项目谥在学习，任何用于违法用途的行为与作者无关。</p>
					
					<p>如果对本项目感兴趣，欢迎加入QQ讨论群：8578575</p>
					
					<p>目前尚处于研阶段，为了方便测试，HTML5做成了单机方式运行，但这并不影响后期部署成多端游戏。</p>

					<p>github: <a href="https://github.com/2881099/FightLandlord" target="_blank">https://github.com/2881099/FightLandlord</a></p>

					<p>&nbsp;</p>
					<p>&nbsp;</p>
				</div>
				<p><Input v-model="playerIds[0]" placeholder="Enter something..." style="width:300px" /></p>
				<p><Input v-model="playerIds[1]" placeholder="Enter something..." style="width:300px" /></p>
				<p><Input v-model="playerIds[2]" placeholder="Enter something..." style="width:300px" /></p>
				<p>
					<Select v-model="multiple" placeholder="玩多大" style="width:200px">
						<Option value="1" :key="1">1元</Option>
						<Option value="5" :key="5">5元</Option>
						<Option value="10" :key="10">10元</Option>
					</Select>
				</p>
				<p>&nbsp;</p>
				<p>
					<Button type="primary" :loading="starting" @click="StartAndShuffle">
						<span v-if="!starting">开始游戏!</span>
						<span v-else>Loading...</span>
					</Button>
				</p>
			</Card>
		</div>

		<div v-if="stage == '叫地主' || stage == '斗地主'" v-for="(player, playerIndex) in ddzdata.players">
			<div style="padding: 20px 20px 0px 20px; height:260px; border:1px solid #ddd;">
				<div style="float:left; width:70%; margin-top:60px; position: absolute;">
					<div v-for="(pk, pkIndex) in player.pokerText"
						@mousedown="mousedownPoker(player, pkIndex, player.poker[pkIndex])"
						@mousemove="mousemovePoker(player, pkIndex, player.poker[pkIndex])"
						@mouseup="mouseupPoker(player, pkIndex, player.poker[pkIndex])"
						class="poker" unselectable="on"
						:style="{ 
                            overflow: 'hidden',
                            cursor: 'pointer', 
							left: (pkIndex + 1) * 32 + 'px',
							top: updateindex> 0 && selectedPokers[player.poker[pkIndex]] ? '-32px' : '', color: (player.poker[pkIndex] < 53 && (player.poker[pkIndex] % 4 == 1 || player.poker[pkIndex] % 4 == 3) || player.poker[pkIndex] == 52 ? 'black' : 'red'),}"
						>
                        <div style="width: 110px;height: 156px; overflow: hidden;">
                            <span class="glyphicon" :name="'CpPcDqQdErReFsSfGtTgHuUhIvViJwWjKxXkLyYlMzZmAnNaBoOb??'[player.poker[pkIndex]]"></span>
                        </div>
					</div>
					<div style="clear:both;"></div>
				</div>
				<div style="float:right;">
					<p style="text-align: right;">{{player.id}} <span :style="{ color: player.role == '地主' ? 'red' : player.role == '农民' ? 'green' : '#aaa'}">【{{player.role}}】</span></p>

					<p v-if="stage == '叫地主' && playerIndex == ddzdata.playerIndex" style="margin-top:36px;">
						<Button v-for="maddtion in ddzdata.multipleAdditionMax"
								v-if="maddtion > ddzdata.multipleAddition" @click="SelectLandlord(player.id, maddtion)" type="primary">
							{{maddtion}}分
						</Button>
						<Button @click="SelectFarmer(player.id)" type="primary">不叫</Button>
					</p>

					<p v-if="stage == '斗地主' && playerIndex == ddzdata.playerIndex" style="margin-top:36px;">
						<Button v-if="ddzdata.chupai.length > 0 && ddzdata.chupai[ddzdata.chupai.length - 1].playerIndex != ddzdata.playerIndex" @click="Pass(player.id)" type="primary">不要</Button>
						<Button @click="Play(player.id)" type="primary">出牌</Button>
						<Button @click="PlayTips(player.id)" type="primary">提示</Button>
					</p>
				</div>
				<div style="clear:both;"></div>
			</div>
		</div>

		<div v-if="stage == '斗地主' || stage == '游戏结束'" style="background:#eee;padding: 20px 20px 0px 20px;">
				<Card :bordered="false">
					<p slot="title">底牌</p>
					<p>
						<span v-for="(pk, pkIndex) in ddzdata.dipaiText"
						:style="{ fontFamily: 'PokerFace', fontSize: '80px', cursor: 'pointer', color: (ddzdata.dipai[pkIndex] < 53 && (ddzdata.dipai[pkIndex] % 4 == 1 || ddzdata.dipai[pkIndex] % 4 == 3) || ddzdata.dipai[pkIndex] == 52 ? 'black' : 'red'),}"
						><!--{{pk}}-->{{'CpPcDqQdErReFsSfGtTgHuUhIvViJwWjKxXkLyYlMzZmAnNaBoOb??'[ddzdata.dipai[pkIndex]]}}</span>
	
						<span v-if="ddzdata.chupai.length > 0 && ddzdata.chupai[ddzdata.chupai.length - 1].result != null" style="margin-left:120px;">
							<span v-for="(pk, pkIndex) in ddzdata.chupai[ddzdata.chupai.length - 1].result.text"
							:style="{ fontFamily: 'PokerFace', fontSize: '60px', cursor: 'pointer', color: (ddzdata.chupai[ddzdata.chupai.length - 1].result.value[pkIndex] < 53 && (ddzdata.chupai[ddzdata.chupai.length - 1].result.value[pkIndex] % 4 == 1 || ddzdata.chupai[ddzdata.chupai.length - 1].result.value[pkIndex] % 4 == 3) || ddzdata.chupai[ddzdata.chupai.length - 1].result.value[pkIndex] == 52 ? 'black' : 'red'),}"
							><!--{{pk}}-->{{'CpPcDqQdErReFsSfGtTgHuUhIvViJwWjKxXkLyYlMzZmAnNaBoOb??'[ddzdata.chupai[ddzdata.chupai.length - 1].result.value[pkIndex]]}}</span>
						</span>
	
						<span v-if="stage == '游戏结束' && ddzdata.chupai.length > 0" style="margin-left:120px;">
							游戏结束, 【{{ddzdata.players[ddzdata.chupai[ddzdata.chupai.length - 1].playerIndex].role}}】 胜利, 
							
							炸弹: {{ddzdata.bong}}, 倍数: {{ddzdata.multipleAddition}}, 金额: {{(ddzdata.bong + 1) * ddzdata.multipleAddition * ddzdata.multiple}}。
						</span>
						<span v-if="stage == '游戏结束' && ddzdata.chupai.length == 0" style="margin-left:120px;">
							游戏结束，没有人当【地主】。
						</span>
					</p>
				</Card>
			</div>
	</div>

<style>
body { margin: 0px; padding: 0px; font-size: 14px; }
@font-face { 
	font-family: PokerFace; 
	src: url('poker.ttf');
}
    .glyphicon:after {
        content: attr(name);        
        margin-left: -13px; 
    }
.poker {
	font-family: PokerFace;
	font-size: 120px;
	/* background-image: url("");
	background-position: 14px 14px;
	background-repeat: no-repeat; */
	position: absolute;
	background-color: white;
	margin: 0px;
	padding: 0px;
	width: 106px;
	height: 142px;
	-webkit-touch-callout: none; /* iOS Safari */
	-webkit-user-select: none; /* Chrome/Safari/Opera */
	-khtml-user-select: none; /* Konqueror */
	-moz-user-select: none; /* Firefox */
	-ms-user-select: none; /* Internet Explorer/Edge */
	user-select: none; /* Non-prefixed version, currently not supported by any browser */
}
    .poker span {
        position: absolute;
        top: -13px;
    }
button {
	padding: 9px;
	
}
</style>
	<script>

		function initvue11() {
			var app = new Vue({
				el: '#app',
				data: {
					starting: false,

					multiple: 1,
					playerIds: ['玩家1', '玩家2', '玩家3'],
					stage: '未开始',
					selectedPokers: {}, //出牌
					playTips: [],//提示出牌
					playTipsIndex: 0, 
					updateindex: 0,

					ddzid: '',
					ddzdata: {
						Bong: 0,
						chupai: [],
						dipai: "Ai8F",
						multiple: 1,
						multipleAddition: 0,
						multipleAdditionMax: 3,
						playerIndex: -1,

						players: [
							{
								player: { Id: '玩家1', Nick: null, Balance: 0, IsOnline: false, GameState: "Idle" },
								poker: [],
								pokerText: [],
								pokerInit: [],
								role: '未知'
							},
							{
								player: { Id: '玩家2', Nick: null, Balance: 0, IsOnline: false, GameState: "Idle" },
								poker: [],
								pokerInit: [],
								role: '未知'
							},
							{
								player: { Id: '玩家3', Nick: null, Balance: 0, IsOnline: false, GameState: "Idle" },
								poker: [],
								pokerInit: [],
								role: '未知'
							}
						]
					},

					mouseDownPlayer: null,
					mouseDownPlayerIndex: 0,
				},

				computed: {

				},

				components: {
				},

				methods: {
					clickPoker(pk) {
						if (this.selectedPokers[pk]) delete this.selectedPokers[pk];
						else this.selectedPokers[pk] = 1;
						this.updateindex++;
					},
					mousedownPoker(player, index, pk) {
						this.mouseDownPlayer = player;
						this.mouseDownPlayerIndex = index;
					},
					mousemovePoker(player, index, pk) {
						
					},
					mouseupPoker(player, index, pk) {
						if (this.mouseDownPlayer === player) {
							var min = Math.min(this.mouseDownPlayerIndex, index);
							var max = Math.max(this.mouseDownPlayerIndex, index);
							for (var a = min; a <= max; a++) {
								if (this.selectedPokers[player.poker[a]]) delete this.selectedPokers[player.poker[a]];
								else this.selectedPokers[player.poker[a]] = 1;
							}
							this.updateindex++;
						}
					},

					StartAndShuffle() {
						this.starting = true;
						var playerIds = [];
						ajax('form', '/ddz/StartAndShuffle', { multiple: this.multiple, playerIds: this.playerIds }).then(rt => {
							if (!rt.success) return alert(rt.message);
							this.ddzid = rt.data.id;
							this.ddzdata = rt.data.data;
							this.stage = this.ddzdata.stage;
						});
					},
					SelectLandlord(playerId, multiple) {
						ajax('form', '/ddz/SelectLandlord', { id: this.ddzid, playerId: playerId, multiple: multiple }).then(rt => {
							if (!rt.success) return alert(rt.message);
							this.ddzdata = rt.data.data;
							this.stage = this.ddzdata.stage;
						});
					},
					SelectFarmer(playerId) {
						ajax('form', '/ddz/SelectFarmer', { id: this.ddzid, playerId: playerId }).then(rt => {
							if (!rt.success) return alert(rt.message);
							this.ddzdata = rt.data.data;
							this.stage = this.ddzdata.stage;
						});
					},
					Play(playerId) {
						var poker = [];
						var allpoker = this.ddzdata.players[this.ddzdata.playerIndex].poker;
						for (var b = 0; b < allpoker.length; b++) {
							if (this.selectedPokers[allpoker[b]]) {
								poker.push(allpoker[b]);
							}
						}
						if (poker.length == 0) return alert('请选择要出的牌');
						ajax('form', '/ddz/Play', { id: this.ddzid, playerId: playerId, poker: poker }).then(rt => {
							if (!rt.success) return alert(rt.message);
							this.ddzdata = rt.data.data;
							this.stage = this.ddzdata.stage;
							this.selectedPokers = {};
							this.playTips.splice(0, this.playTips.length);
							this.playTipsIndex = 0;
						});
					},
					Pass(playerId) {
						ajax('form', '/ddz/Pass', { id: this.ddzid, playerId: playerId }).then(rt => {
							if (!rt.success) return alert(rt.message);
							this.ddzdata = rt.data.data;
							this.stage = this.ddzdata.stage;
							this.selectedPokers = {};
							this.playTips.splice(0, this.playTips.length);
							this.playTipsIndex = 0;
						});
					},
					PlayTips(playerId) {
						if (this.playTips.length == 0) {
							ajax('form', '/ddz/PlayTips', { id: this.ddzid, playerId: playerId }).then(rt => {
								if (!rt.success) return alert(rt.message);
								this.ddzdata = rt.data.data;
								this.stage = this.ddzdata.stage;
								this.selectedPokers = {};
								this.playTips.splice(0, this.playTips.length);
								this.playTipsIndex = 0;
								for (var a = 0; a < rt.data.tips.length; a++) this.playTips.push(rt.data.tips[a]);
								if (this.playTips.length == 0) {
									this.Pass(playerId);
								} else {
									this.NextPlayTips();
								}
							});
						} else {
							this.NextPlayTips();
						}
					},
					NextPlayTips() {
						if (this.playTipsIndex >= this.playTips.length) return;
						this.selectedPokers = {};
						this.updateindex++;
						var tips = this.playTips[this.playTipsIndex];
						for (var a = 0; a < tips.length; a++) this.selectedPokers[tips[a]] = 1;
						this.updateindex++;
						this.playTipsIndex++;
						if (this.playTipsIndex >= this.playTips.length) this.playTipsIndex = 0;
					}
				},

				created() {
				}
			})
		}

		var apipath = '';
		function ajax(type, url, data, header, dataType) {

			return new Promise((resolve, reject) => {
				if (!header) header = {};
				header.token = localStorage.getItem('token');
				if (!header.token) delete header.token;
				while (url[0] == '/') url = url.substring(1);
				ajaxRequest(type, apipath + '/' + url, data, resolve, function (d) {
					if (d.code === 5009) localStorage.setItem('token', null); /*登陆TOKEN失效_请重新登陆*/
					d.url = type + ' ' + url;
					console.log(d);
					if ((d.code === 5009 || d.code === 5001) && !top.istmpreload) {
						top.istmpreload = true;
						alert('请重新登陆');
						top.location.href = '/';
					}
					resolve(d);
				}, header, dataType);
			});
		};
		function ajaxRequest(type, url, data, callback, failCallBack, header, dataType) {
			var url_encode = function (str) {
				return encodeURIComponent(str)
					.replace(/ /gi, '+')
					.replace(/~/gi, '%7e')
					.replace(/'/gi, '%26%2339%3b');
			};

			type = String(type || 'GET').toUpperCase();
			if (type == 'GET') {
				var dataStr = typeof (data) === 'string' ? data : '';
				if (typeof (data) === 'object')
					for (var key in data) {
						if (Object.prototype.toString.call((data[key])) == '[object Array]') {
							for (var a = 0; a < data[key].length; a++)
								if (data[key][a] !== undefined) dataStr += '&' + key + '=' + url_encode(data[key][a]);
						}
						if (data[key] !== "" && data[key] !== null) dataStr += '&' + key + '=' + url_encode(data[key]);
					}

				if (dataStr !== '') {
					dataStr = dataStr.substr(1);
					url = url + '?' + dataStr;
				}
			}
			var sendData = '';
			var contentType = 'application/x-www-form-urlencoded; charset=utf-8';
			if (type == "FORM") {
				if (typeof (data) === 'string') sendData = data;
				if (typeof (data) === 'object')
					for (var key in data) {
						if (Object.prototype.toString.call((data[key])) == '[object Array]') {
							for (var a = 0; a < data[key].length; a++)
								if (data[key] !== undefined) sendData += '&' + key + "=" + url_encode(data[key][a]);
						} else if (data[key] !== "" && data[key] !== null) sendData += '&' + key + "=" + url_encode(data[key]);
					}
				if (sendData !== '') sendData = sendData.substr(1);
			}
			if (type == 'JSON') {
				sendData = JSON.stringify(data);
				contentType = "application/json; charset=utf-8";
			}
			if (!failCallBack) failCallBack = console.log;
			var requestObj = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject;
			requestObj.onreadystatechange = () => {
				if (requestObj.readyState == 4) {
					if (requestObj.status == 200) {
						var obj = requestObj.response
						if (String(dataType).toLowerCase() === 'html') return callback(obj);
						if (typeof obj !== 'object') obj = JSON.parse(obj);
						if (obj.code === 0) return callback(obj);
						failCallBack(obj);
					} else {
						failCallBack(requestObj)
					}
				}
			};
			requestObj.open(type == 'GET' ? type : 'POST', url, true);
			if (type != 'GET') requestObj.setRequestHeader("Content-type", contentType);
			if (typeof (header) === 'object')
				for (var key in header) requestObj.setRequestHeader(key, header[key]);
			requestObj.send(sendData || null);
		}

		String.prototype.trim = function () {
			return this.ltrim().rtrim();
		}
		String.prototype.ltrim = function () {
			return this.replace(/^\s+(.*)/g, '$1');
		}
		String.prototype.rtrim = function () {
			return this.replace(/([^ ]*)\s+$/g, '$1');
		}
		//中文按2位算
		String.prototype.getLength = function () {
			return this.replace(/([\u0391-\uFFE5])/ig, '11').length;
		}
		String.prototype.left = function (len, endstr) {
			if (len > this.getLength()) return this;
			var ret = this.replace(/([\u0391-\uFFE5])/ig, '$1\0')
				.substr(0, len).replace(/([\u0391-\uFFE5])\0/ig, '$1');
			if (endstr) ret = ret.concat(endstr);
			return ret;
		}
		String.prototype.format = function () {
			var val = this.toString();
			for (var a = 0; a < arguments.length; a++) val = val.replace(new RegExp("\\{" + a + "\\}", "g"), arguments[a]);
			return val;
		}
		var __padleftright = function (str, len, padstr, isleft) {
			str = str || ' ';
			padstr = padstr || '';
			var ret = [];
			for (var a = 0; a < len - str.length; a++) ret.push(padstr);
			if (isleft) ret.unshift(this)
			else ret.push(this);
			return ret.join('');
		}
		// 'a'.padleft(3, '0') => '00a'
		String.prototype.padleft = function (len, padstr) {
			return __padleftright(this, len, padstr, 1);
		};
		// 'a'.padright(3, '0') => 'a00'
		String.prototype.padright = function (len, padstr) {
			return __padleftright(this, len, padstr, 0);
		};
		Function.prototype.toString2 = function () {
			var str = this.toString();
			str = str.substr(str.indexOf('/*') + 2, str.length);
			str = str.substr(0, str.lastIndexOf('*/'));
			return str;
		};
		Number.prototype.round = function (r) {
			r = typeof (r) == 'undefined' ? 1 : r;
			var rv = String(this);
			var io = rv.indexOf('.');
			var ri = io == -1 ? '' : rv.substr(io + 1, r);
			var le = io == -1 ? (rv + '.') : rv.substr(0, io + 1 + r);
			for (var a = ri.length; a < r; a++) le += '0';
			return le;
		};
		Date.prototype.toString = function (f) {
			function tempfunc(opo, pos) {
				var val = '';
				opo = String(opo);
				for (var a = 1; a < arguments.length; a++) {
					var chr = opo.charAt(arguments[a] - 1);
					val += chr;
				}
				return val;
			}

			if (!f) f = 'yyyy-MM-dd HH:mm:ss';
			var year = this.getFullYear();
			var h12 = this.getHours() > 12 ? (this.getHours() - 12) : this.getHours()
			var tmp = {
				'yyyy': year,
				'yy': tempfunc(year, 3, 4),
				'MM': (this.getMonth() < 9 ? '0' : '') + (this.getMonth() + 1),
				'M': this.getMonth() + 1,
				'dd': (this.getDate() < 10 ? '0' : '') + this.getDate(),
				'd': this.getDate(),
				'hh': (h12 < 10 ? '0' : '') + h12,
				'h': h12,
				'HH': (this.getHours() < 10 ? '0' : '') + this.getHours(),
				'H': this.getHours(),
				'mm': (this.getMinutes() < 10 ? '0' : '') + this.getMinutes(),
				'm': this.getMinutes(),
				'ss': (this.getSeconds() < 10 ? '0' : '') + this.getSeconds(),
				's': this.getSeconds()
			};

			for (var p in tmp) f = f.replace(new RegExp('\\b' + p + '\\b', 'g'), tmp[p]);
			return f;
		}
		Date.prototype.timespan = function () {
			var sec = (new Date().getTime() - this.getTime()) / 1000;
			if (sec < 5) return '刚刚';
			if (sec < 60) return Math.floor(sec) + '秒前';
			var min = sec / 60;
			if (min < 60) return Math.floor(min) + '分钟前';
			var hou = min / 60;
			if (hou < 24) return Math.floor(hou) + '小时前';
			var day = hou / 24;
			if (day < 30) return Math.floor(day) + '天前'
			var mon = day / 30;
			if (mon < 12) return Math.floor(mon) + '个月前';
			return Math.floor(day / 365) + '年前';
		};
		initvue11();
	</script>
</body>
</html>
